
package fag.core.game.test;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;

import fag.core.collision.Collision;
import fag.core.game.Camera;
import fag.core.game.Doodad;
import fag.core.game.Game;
import fag.core.game.Scene;
import fag.core.geometry.Rectangle2D;
import fag.core.geometry.Vector2D;

public class Multiball extends Game implements MouseMotionListener, MouseListener {	
	
	public static final int WIDTH = 800;
	public static final int HEIGHT = 600;
	
	/**
	 * Point d'entrée du programme.
	 * @param args Les arguments du programme.
	 */
	public static void main(String[] args) {
		
		Multiball multiball = new Multiball();
		multiball.start();
		
		JFrame frame = new JFrame();
		frame.setVisible(true);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		frame.add(multiball.getCamera());
		frame.pack();
	}
	
	private MultiballHud hud = new MultiballHud();
	
	private Scene scene = new Scene(new Rectangle2D(-100, -100, WIDTH + 200, HEIGHT + 200));
	
	private Doodad racket = new Doodad(new RacketModel());
	
	private List<Ball> balls = new ArrayList<Ball>();
	
	/**
	 * Constructeur du jeu.
	 * Initialisation du niveau et des doodads.
	 */
	public Multiball() {
		
		addScene(scene);
		scene.addCamera(hud);
		
		hud.setSize(WIDTH, HEIGHT);
		
		// Raquette
		scene.addDoodad(racket);
		racket.setLocation(new Vector2D(Math.random() * WIDTH, Math.random() * HEIGHT));	
		// Balles
		for(int i = 0; i < 100; ++i) {
			Ball ball = new Ball();
			scene.addDoodad(ball);
			balls.add(ball);
			ball.setLocation(Math.random() * WIDTH, Math.random() * HEIGHT);	
		}
		
		// Ajout des listeners
		hud.addMouseListener(this);
		hud.addMouseMotionListener(this);
	}
	
	/**
	 * Accesseur de la caméra du jeu.
	 * @return La caméra du jeu.
	 */
	public Camera getCamera() {
		return hud;
	}
	
	@Override
	public void step(double dt) {
		
		// Affichage du fps
		hud.setFps(getAverageFps());
		
		// Collisions entre les balles
		for(int i = 0; i < balls.size() - 1; ++i) {
			for(int j = i + 1; j < balls.size(); ++j) {
				
				Ball a = balls.get(i);
				Ball b = balls.get(j);
				
				Collision collision = a.getHitbox().getCollision(b.getHitbox());
				
				if(collision.isColliding()) {
					
					Vector2D normal = collision.getNormal();
					
					a.setLocation(a.getLocation().add(normal.mul(collision.getPenetration() * -0.6)));
					b.setLocation(b.getLocation().add(normal.mul(collision.getPenetration() * 0.6)));
					a.bounce(normal);
					b.bounce(normal.mul(-1));
				}
			}
		}
		
		// Collisions entre les balles et la raquette
		for(int i = 0; i < balls.size(); ++i) {
			
			Ball ball = balls.get(i);
			
			Collision collision = racket.getHitbox().getCollision(ball.getHitbox());
			
			if(collision.isColliding()) {
				
				Vector2D normal = collision.getNormal();
				
				ball.setLocation(ball.getLocation().add(normal.mul(collision.getPenetration() * 1.1)));
				ball.bounce(normal.mul(-1));
			}
		}
		
		
		for(Ball ball : balls) {
			
			// Collisions avec le bord de l'écran
			if(ball.getX() < 0) {
				ball.setLocation(1, ball.getY());
				ball.bounce(new Vector2D(1, 0));
			}
			else if(ball.getX() > WIDTH - 32) {
				ball.setLocation(WIDTH - 32 - 1, ball.getY());
				ball.bounce(new Vector2D(-1, 0));
			}
			
			if(ball.getY() < 0) {
				ball.setLocation(ball.getX(), 1);
				ball.bounce(new Vector2D(0, 1));
			}
			else if(ball.getY() > HEIGHT - 32) {
				ball.setLocation(ball.getX(), HEIGHT - 32 - 1);
				ball.bounce(new Vector2D(0, -1));
			}
			
			// Déplacer les balles
			ball.step(dt / 1000);
		}
	}

	@Override
	public void mouseClicked(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mousePressed(MouseEvent e) {
	}

	@Override
	public void mouseReleased(MouseEvent e) {
	}

	@Override
	public void mouseDragged(MouseEvent e) {
	}

	@Override
	public void mouseMoved(MouseEvent e) {

		racket.setLocation(e.getX() - racket.getBounds().getWidth() / 2, e.getY() - racket.getBounds().getHeight() / 2);
	}
}
